/*--
 * Configuration.cs: Provides configuration data for the rest of the Metashell system.
 *--
 * Note: This implementation uses the Win32 registry, or, if using Mono, an emulation using XML.
 *       This might be changed in future versions.
 *--
 * For more information, please visit the Metashell Project site:
 *   http://code.google.com/p/metashell/
 *--
 * (c) 2006 Christopher E. Granade.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; exactly version 2
 * of the License applies to this software.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

using System;
using System.IO;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Xsl;

using Microsoft.Win32;

using Metashell.Core.Utility;

namespace Metashell.Core {
	
	/// This class abstracts all the hard work of figuring out the configuration of the system.
	/// The class should be called from the Preferences class.
	internal static class Configuration {
		
		#region Constants
		
			private const string
				registryPath = 
					@"SOFTWARE\Metashell",
				settingsPath =
					registryPath + @"\Settings",
				preferencesPath =
					registryPath + @"\Preferences",
				homePref =
					"paths.homedir",
				pluginPathsPath =
					settingsPath + @"\PluginPaths",
				transformsCat =
					"transforms",
				coreDirSetting =
					"CoreDir",
				resDirSetting =
					"ResourceDir",
				appName =
					"metashell";
					
			private static RegistryKey
				settingsKey =
					Registry.CurrentUser.CreateSubKey(settingsPath),
				preferencesKey =
					Registry.CurrentUser.CreateSubKey(preferencesPath),
				pluginPathsKey =
					Registry.CurrentUser.CreateSubKey(pluginPathsPath);
		
		#endregion
		
		#region Public Methods
		
			public static string GetCoreAppDirectory() {
			
				return (string)settingsKey.GetValue(coreDirSetting,
					Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
						+ Path.DirectorySeparatorChar.ToString()
						+ appName);
				
            }
            
            public static string GetResourceDirectory() {
                
                return (string)settingsKey.GetValue(resDirSetting,
                	GetCoreAppDirectory() + Path.DirectorySeparatorChar.ToString() + "res");
                
            }
            
            public static Dictionary<Pair<string, string>, XslCompiledTransform> GetTransforms() {
			
				// Transforms are stored as preferences of the form:
				// transform.<from>.<to>
				
				// Let's pull in the entire category.
				Dictionary<string, string> transformPrefs = GetPreferences(transformsCat);
				
				// Now, for each, let's pull in each document.
				Dictionary<Pair<string, string>, XslCompiledTransform> transforms =
					new Dictionary<Pair<string, string>, XslCompiledTransform>();
				
				foreach (KeyValuePair<string, string> keyval in transformPrefs) {
					
					// Convert the name into a Pair of strings.
					Pair<string, string> key = StringToPair(keyval.Key);					
				
					XslCompiledTransform xct = new XslCompiledTransform();
					xct.Load(XML.LoadXMLFromFile(keyval.Value));
					
					transforms.Add(key, xct);
					
				}
				
				return transforms;
				
				
			}
			
			public static List<string> GetCommandPluginPaths() {
				
				// First, find any and all directories.
				List<string> assemblyNames = new List<string>();
				Dictionary<string, object> regvalues =
					RegistryUtils.GetValuesFromRegistryKey(pluginPathsKey);
				
				foreach (KeyValuePair<string, object> regvalue in regvalues) {
					// Now, then... search the directory for files whose names end in .dll.
					string dir = (string)regvalue.Value;
					
					try {
						string[] files = Directory.GetFiles(dir);
						
						// Look at each bloody file.
						foreach (string file in files) {
							if (file.EndsWith(".dll")) {
								assemblyNames.Add(file);
							}
						}
					} catch (Exception e) {
						System.Console.WriteLine(e.Message);
					}
					
				}
				
				return assemblyNames;
				
			}
			
			// Preference format:
			//
			//   category[.subcategory].prefname
			//
			// Note that [.subcategory] may be repeated ad nauseum.
			//
			// No, this isn't in a Registry-like format. The idea is to make a more general
			// specification that could be ported to whatever engine. This class may be moved from the
			// Registry-based implmentation it uses now.
			public static string GetPreference(string preferenceName, string defvalue) {
			
				// Seperate out the category. If we can't, throw a friggin' exception.
				string cat = preferenceName.Substring(0, preferenceName.IndexOf('.'));
				
				if (cat.Length == 0) { throw new Exception("Invalid preference name."); }
				
				// Now open that key.
				RegistryKey rk = preferencesKey.CreateSubKey(cat);
				
				return (string)rk.GetValue(preferenceName.Substring(preferenceName.IndexOf('.') + 1), defvalue);
				
			}
			
			public static void SetPreference(string preferenceName, string newvalue) {
				
				// Seperate out the category. If we can't, throw a friggin' exception.
				string cat = preferenceName.Substring(0, preferenceName.IndexOf('.'));
				
				if (cat.Length == 0) { throw new Exception("Invalid preference name."); }
				
				// Now open that key.
				RegistryKey rk = preferencesKey.CreateSubKey(cat);
				
				rk.SetValue(preferenceName.Substring(preferenceName.IndexOf('.') + 1), newvalue);
				
			}
			
			public static Dictionary<string, string> GetPreferences(string category) {
				
				RegistryKey rk = preferencesKey.CreateSubKey(category);
				
				return ConvertDictValuesToString<string>(
					RegistryUtils.GetValuesFromRegistryKey(rk));
				
			}
		
			public static string GetHomeDirectory() {
				
				// We'd use 
				return GetPreference(homePref,
					Environment.GetFolderPath(Environment.SpecialFolder.Personal));
				
			}
		
		#endregion
		
		private static Pair<string, string> StringToPair(string str) {
			
			Pair<string, string> pair;
			
			pair.First = str.Substring(0, str.IndexOf('.'));
			pair.Second = str.Substring(str.IndexOf('.') + 1);
			
			return pair;
			
		}		
		
		private static Dictionary<T, string> ConvertDictValuesToString<T>(Dictionary<T, object> indict) {
			
			Dictionary<T, string> outdict = new Dictionary<T, string>();
			
			foreach (KeyValuePair<T, object> dictpair in indict) {
				outdict.Add(dictpair.Key, dictpair.Value.ToString());
			}
			
			return outdict;
			
		}
		
		
		
	}
	
}
